<!DOCTYPE html>
<html>
<head>
<meta name="viewport"
	content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<meta charset="UTF-8">
<title>消除过期对象的引用与内存泄漏</title>
<meta name="Keywords" content="消除对象的引用，内存泄漏" />
<meta name="Description" content="" />

</head>
<link type="text/css" rel="stylesheet" href="../styles/main_text.css" />
<body>
	<div class="content">

		<a href="../index.html">目录</a> > <a href="../effective_java.html">高效Java</a>
		<h1>消除过期对象的引用与内存泄漏</h1>
		<span>请尊重版权！ 如需转载，请联系<a href="#wechat">作者<a />。</span>
		<hr style="margin-bottom: 50px;" />
		<div class="main_text">
			<p>Java的内存回收机制是一个创举，相比起c或c++手动回收内存来说，极大提高了开发效率和程序的稳定性。但是并不代表，Java工程师可以不关心内存回收了，很多人以为自己了解内存回收，但内存回收其实是个相当隐晦的，可能也是一个复杂的问题，所以，不要轻视它。</p>
			<h2>过期引用&无意识的对象保持</h2>
			<div class="code_area">
			<span><span style="color: red">[程序清单01] </span>过期引用引发的"内存泄漏"<i>（加引号是因为，它并不是一种严格意义上的内存泄漏）</i></span>
			<pre class="brush: java">
import java.util.Arrays;
import java.util.EmptyStackException;

public class Stack {

	private Object[] elements;
	private int size = 0;
	private static final int DEFAULT_INITIAL_CAPACITY = 16;

	public Stack() {
		elements = new Object[DEFAULT_INITIAL_CAPACITY];
	}

	public void push(Object e) {
		ensureCapacity();
		elements[size++] = e;
	}

	public Object pop() {
		if (size == 0) {
			throw new EmptyStackException();
		}
		return elements[--size];
	}

	private void ensureCapacity() {
		if (elements.length == size) {
			elements = Arrays.copyOf(elements, 2 * size + 1);
		}
	}
}
			</pre>
			</div>
			<p>
				如果你是一个很有经验的工程师，可以看出在这段代码中pop方法中代码的问题。当从栈中弹出一个对象后，size减1，
				此时如果之前elements[size]=object1，那么此时，elements的size角标上的内存地址依然指向object1，处于被引用状态。
				在Java的内存回收机制中，被引用的对象不会被回收。这类对象被称为<b>过期引用</b>。同时这种隐蔽的内存泄漏被归纳为<b>无意识的对象保持</b>。
			</p>
			<p>
				解决方法很简单，看以下的代码<i>（这段代码，这种处理方式，你可以在JDK中的Vectoer类中看到）</i><br />
			</p>
			<pre class="brush:java">
public Object pop() {
    if (size == 0) {
        throw new EmptyStackException();
    }
    elements[size] = null;//清除过期引用
    return elements[--size];
}
</pre>
			<p>
				如果你是一个新手，看到以上的代码，或者遇到了上面的情况，可能会使自己变得过于小心甚至被困扰：会时长考虑，是不是需要清除每一个不再使用的对象引用。
				当然，这种做法是不必要也不提倡的。<b>这种将一个引用对象置空的做法，应该是一种特殊情况的处理方法，不是一种开发中的规范行为。对于一般的场景，他是不必要并且多余的，你的代码也会因此看起来乱七八糟。</b>但是，你必须明白是谁在管理内存，是你？还是JVM？！
			</p>
			<p>一般而言，在方法体中声明的局部变量，其是由JVM来管理内存的，在方法结束后，其会在gc时被清除。涉及到引用全局变量的时候，要特别注意无意识的对象保持所造成的内存泄漏。
			</p>
			<p>以下是另外一个例子，
				业务场景是，用户点击一条商品后，传入user和skuId，返回和当前商品相关的商品。并把当前的id加到结果集合中。</p>
			<br /> <span><span style="color: red">[程序清单02] </span>另外一个无意识的对象保持</span>
			<pre class="brush:java">
class Demo2 {

	private static Map&lt;String, List&lt;String&gt;&gt; data = new ConcurrentHashMap&lt;&gt;();
	private static Demo2 instance = new Demo2();

	private Demo2() {
		loadData2Memery();
	}

	public static Demo2 getInstance() {
		return instance;
	}

	private void loadData2Memery() {
		// some code ,put("key",list)
		List&lt;String&gt; elements = new ArrayList&lt;&gt;();
		elements.add("sku3");
		elements.add("sku2");
		data.put("user1", elements);
	}

	public List&lt;String&gt; get(String key) {
		return data.get("key1");
	}
}

class AContoller {

	public void method1(String userId,String sku) {
		List&lt;String&gt; list = Demo2.getInstance().get(userId);
		list.add(sku);
		queryRedis(list);
	}

	public List&lt;String&gt; queryRedis(List&lt;String&gt; keys) {
		List&lt;String&gt; data = null;
		//query redis and return data
		return data;
	}
}
			</pre>
			<p>此时这种无意识的对象保持，会在高并发的时候，使list越来越大。
			</p>
		</div>
		<hr style="margin-top: 50px;" />
		<p>
			<span style="color: red">反馈、纠错：请通过底部的wechat发送给我，来完善此页面，帮助更多的人学习。</span>
		</p>
		<p><a href="/tks.html">鸣谢</a></p>
		<div style="margin-bottom: 50px;">
				<table>
					<tr>
						<td style="font-weight: 300" height="" width="200px">
							<div
								style="margin-top: 10px;">
								加好友 <img style="margin-top: 5px;" id="wechat" width="170px;" src="../imgs/wechat.png">
								<br />扫描分享到朋友圈
								<p id="qrcode" style="margin-top: 5px;width: 185px; height: 188px; margin: 0;"></p>
								<script type="text/javascript" src="../scripts/qrcode.min.js">
									
								</script>
								<script type="text/javascript" src="../scripts/jquery.min.js"></script>
								<script type="text/javascript">
									var qrcode = new QRCode(document
											.getElementById("qrcode"), {
										width : 170,
										height : 170
									});

									function makeCode() {
										qrcode.makeCode(window.location.href);
									}
									makeCode();
								</script>

							</div>
						</td>
						<td>
							<div
								style="margin-top: 10px; margin-left: 100px; background: rgba(224, 224, 224, 0.22); border: 1px solid rgba(224, 224, 224, 0.22);">
								<div style="margin: 20px;">
									<p style="font-weight: 300">打赏
									<p style="color: blue">如果文中的技术在企业开发中，解决了你的问题，或者避免了你踩坑，请你付费观看，建议30元，但是这不是强制的。针对学生免费。

									
									<div>
										<img width="200px;" src="../imgs/we_pay.png"><img
											width="200px;" src="../imgs/ali_pay.png">

									</div>
								</div>
							</div>
						</td>
					</tr>
					<tr>

					</tr>
				</table>
			</div>
		<!--底部 end  -->
	</div>
</body>

<script type="text/javascript" src="../scripts/XRegExp.js"></script>
<!-- XRegExp is bundled with the final shCore.js during build -->
<script type="text/javascript" src="../scripts/shCore.js"></script>
<script type="text/javascript" src="../scripts/shBrushJScript.js"></script>
<script type="text/javascript" src="../scripts/shBrushJava.js"></script>
<link type="text/css" rel="stylesheet" href="../styles/shCore.css" />
<link type="text/css" rel="Stylesheet"
	href="../styles/shThemeDefault.css" />
<script type="text/javascript">
	//SyntaxHighlighter.all();
</script>

</html>
<script>
	function IsPC() {
		var userAgentInfo = navigator.userAgent;
		var Agents = [ "Android", "iPhone", "SymbianOS", "Windows Phone",
				"iPod" ];
		var flag = true;
		for (var v = 0; v < Agents.length; v++) {
			if (userAgentInfo.indexOf(Agents[v]) > 0) {
				flag = false;
				break;
			}
		}
		if (window.screen.width >= 768) {
			flag = true;
		}
		return flag;
	}
	if (!IsPC()) {
		$(".content").css("width", "100%");
		$("img").css("width", "100%");
		$("pre").css("width", "100%");
		$("pre").css("overflow", "auto");
		/**
		$("pre").css("white-space", "pre-wrap");
		$("pre").css("word-wrap", "break-word");
		 **/

	} else {
		SyntaxHighlighter.all();
	}
</script>